package com.shijie.sjoj.model.component;

import com.shijie.sjoj.model.utils.ArrayUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * LocalDateTime日期时间填充Aop
 *
 * @author ZSJ
 */
@Slf4j
@Aspect
public class LocalDateTimeFillAop {

    /**
     * 切入点表达式
     */
    @Pointcut(value = "@annotation(com.shijie.sjoj.model.component.LocalDateTimeFillAop.LocalDateTimeFill))")
    private void LocalDateTimeFillPointcut() {
    }

    /**
     * 前置通知
     *
     * @param joinPoint JoinPoint
     */
    @Before(value = "LocalDateTimeFillPointcut()")
    private void beforeLocalDateTime(JoinPoint joinPoint) {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取切入注解的值
        String[] values = signature.getMethod().getAnnotation(LocalDateTimeFill.class).value();
        // 获取方法参数列表
        Object[] args = joinPoint.getArgs();
        // 验证参数
        if (ArrayUtils.notEmpty(args)) {
            log.error("--- LocalDateTimeFillAop 填充参数错误，args：{}", Arrays.toString(args));
            return;
        }
        // 规定第一个参数为包含填充字段的实体对象参数
        Object fillEntity = args[0];
        // 准备日期时间填充
        for (String value : values) {
            try {
                // 获取注解中指定的方法(一般为Setter方法或其他可更改字段值的方法)
                Method method = fillEntity.getClass().getDeclaredMethod(value, LocalDateTime.class);
                // 设置权限，不受方法修饰符限制
                method.setAccessible(true);
                // 填充日期时间
                method.invoke(fillEntity, LocalDateTime.now());
            } catch (Exception e) {
                log.error("--- LocalDateTimeFill 填充失败：{} -> {}", value, e.getMessage());
            }
        }
    }


    /**
     * LocalDateTime日期时间填充Aop注解
     *
     * @author ZSJ
     */
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface LocalDateTimeFill {

        /**
         * 需要使用的填充方法
         *
         * @return String[]
         */
        String[] value() default {""};

        /**
         * 可用于字段名createTime
         */
        String CREATE_TIME = "setCreateTime";

        /**
         * 可用于字段名updateTime
         */
        String UPDATE_TIME = "setUpdateTime";

        /**
         * 可用于字段名putTime
         */
        String PUT_TIME = "setPutTime";

        /**
         * 可用于字段名registerTime
         */
        String REGISTER_TIME = "setPutTime";

    }


}